什么是作用域
来一段《你不知道的JavaScript-上卷》中的原话:
几乎所有编程语言最基本的功能之一,就是能够储存变量当中的值,并且能在之后对这个 值进行访问或修改,这些变量住在哪里?换句话说,它们储存在哪里?最重要的是,程序需要时如何找到它们?这些问题说明需要一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量。这套规则被称为作用域
总之就是作用域就是一套规则,这个规则规定了程序如何去找到变量
词法作用域
先看一个例子:
function func1() {
console.log(index)
}
function func2() {
var index = 10
func1()
}
var index = 100
func2() // 100
为啥是100而不是10呢???
因为JavaScript是词法作用域
词法作用域简单地说就是:函数的作用域在声明的时候就决定好了。和词法作用域相对的是动态作用域,动态作用域关注函数从何处调用
上面的代码中,声明func1时,它就处于全局作用域中,所以index就是100,即使执行func1时也是。
函数作用域和块作用域
前面讲了JavaScript是词法作用域,那么什么时候会创建作用域呢???
JavaScript主要是基于函数级别的作用域,也就是每一个函数都会创建一个作用域。为什么说主要呢?因为with和try-catch语句也实现了块作用域,当然了用的很少。
var flag = true;
if (flag) {
var num = 10
}
console.log(num) // 10
如果有块级作用域的话,此时打印num应该报错
function funcLevelScope() {
var index = 10
}
console.log(index); // ReferenceError
因为是函数级别的作用域,所以在函数外面访问不到函数内部的变量
如何模拟块作用域
当然了,第一反应就是在代码外面加上包装函数不就行了,比如这样子:
function scope() {
var flag = true;
if (flag) {
var num = 10
}
}
console.log(num) // ReferenceError
但是此时的问题就是多了一个函数包装,且我们可以随意的去运行scope函数,这可能会造成不好的影响。
自执行函数解决了这个问题:
(function scope() {
var flag = true;
if (flag) {
var num = 10
}
})()
scope() // ReferenceError
console.log(num) // ReferenceError
包装函数的声明以 (function... 而不仅是以 function... 开始。尽管看上去这并不 是一个很显眼的细节,但实际上却是非常重要的区别。函数会被当作函数表达式而不是一个标准的函数声明来处理。
作用域内声明提升
变量声明提升
首先明确的是
var x = 10
像这样一句代码可以分为声明和赋值两句:
var x
x = 10
明确这个概念再继续学习
console.log(x) // undefined
var x = 10
为什么不直接报错呢?
因为上面的代码片段等于:
var x // 声明提前
console.log(x)
x = 10
注意到变量的声明提前到了当前作用域的最前面
函数声明提升
hoist() // hoist!
function hoist() {
console.log("hoist!")
}
为啥函数会成功执行了,因为上面的代码片段相当于:
function hoist() {
console.log("hoist!")
}
hoist()
函数声明被提升到了作用域的最前面
那么函数表达式会被提升吗??
hoist() // TypeError
var hoist = function () {
console.log("hoist")
}
因为这个相当于:
var hoist
hoist() // TypeError
hoist = function () {
console.log("hoist")
}
变量声明提升和函数声明提升的优先级
先说结论:函数会首先被提升,然后才是变量
看例子:
console.log(x)
var x = 10
function x() {
console.log('func x')
}
显然此时打印的x是一个函数
这是因为上面的代码片段相当于:
function x() {
console.log('func x')
}
var x
console.log(x) // f x(){...}
x = 10
所以打印的是函数
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。